package java核心及工具类;

//《enum》  enumerate
//为了让编译器能自动检查某个值在枚举的集合内，并且，不同用途的枚举需要不同的类型来标记，不能混用，我们可以使用enum来定义枚举类：

// enum
//public class 枚举类 {
//    public static void main(String[] args) {
//        Weekday day = Weekday.SUN;
//        if (day == Weekday.SAT || day == Weekday.SUN) {
//            System.out.println("Work at home!");
//        } else {
//            System.out.println("Work at office!");
//        }
//    }
//}
//
//enum Weekday {
//    SUN, MON, TUE, WED, THU, FRI, SAT;
//}

//注意到定义枚举类是通过关键字enum实现的，我们只需依次列出枚举的常量名。和int定义的常量相比，使用enum定义枚举有如下好处：
//
//首先，enum常量本身带有类型信息，即Weekday.SUN类型是Weekday，编译器会自动检查出类型错误。例如，下面的语句不可能编译通过：
//
//int day = 1;
//if (day == Weekday.SUN) { // Compile error: bad operand types for binary operator '=='
//}
//其次，不可能引用到非枚举的值，因为无法通过编译。
//
//最后，不同类型的枚举不能互相比较或者赋值，因为类型不符。例如，不能给一个Weekday枚举类型的变量赋值为Color枚举类型的值：
//
//Weekday x = Weekday.SUN; // ok!
//Weekday y = Color.RED; // Compile error: incompatible types
//这就使得编译器可以在编译期自动检查出所有可能的潜在错误。


//《enum的比较》
//使用enum定义的枚举类是一种引用类型。前面我们讲到，引用类型比较，要使用equals()方法，如果使用==比较，它比较的是两个引用类型的变量是否是同一个对象。
//因此，引用类型比较，要始终使用equals()方法，但enum类型可以例外。这是因为enum类型的每个常量在JVM中只有一个唯一实例，所以可以直接用==比较：
//
//if (day == Weekday.FRI) { // ok!
//}
//if (day.equals(Weekday.SUN)) { // ok, but more code!
//}

//《enum类型》
//通过enum定义的枚举类，和其他的class有什么区别？
//
//答案是没有任何区别。enum定义的类型就是class，只不过它有以下几个特点：
//
//定义的enum类型总是继承自java.lang.Enum，且无法被继承；
//只能定义出enum的实例，而无法通过new操作符创建enum的实例；
//定义的每个实例都是引用类型的唯一实例；
//可以将enum类型用于switch语句。
//
//例如，我们定义的Color枚举类：
//public enum Color {
//    RED, GREEN, BLUE;
//}
//
//编译器编译出的class大概就像这样：
//public final class Color extends Enum { // 继承自Enum，标记为final class
//    // 每个实例均为全局唯一:
//    public static final Color RED = new Color();
//    public static final Color GREEN = new Color();
//    public static final Color BLUE = new Color();
//    // private构造方法，确保外部无法调用new操作符:
//    private Color() {}
//}
//所以，编译后的enum类和普通class并没有任何区别。但是我们自己无法按定义普通class那样来定义enum，必须使用enum关键字，这是Java语法规定的。
//
//因为enum是一个class，每个枚举的值都是class实例，因此，这些实例有一些方法：

//--name()   返回常量名
//--values() 返回枚举类中所有的值。
//--ordinal()方法可以找到每个枚举常量的索引，就像数组索引一样。
//--valueOf()方法返回指定字符串值的枚举常量。

//《name()》
//返回常量名，例如：
//String s = Weekday.SUN.name(); // "SUN"
//
//《ordinal()》
//返回定义的常量的顺序，从0开始计数，例如：
//int n = Weekday.MON.ordinal(); // 1
//改变枚举常量定义的顺序就会导致ordinal()返回值发生变化。例如：
//public enum Weekday {
//    SUN, MON, TUE, WED, THU, FRI, SAT;
//}
//和
//public enum Weekday {
//    MON, TUE, WED, THU, FRI, SAT, SUN;
//}
//的ordinal就是不同的。如果在代码中编写了类似if(x.ordinal()==1)这样的语句，就要保证enum的枚举顺序不能变。新增的常量必须放在最后。
//有些童鞋会想，Weekday的枚举常量如果要和int转换，使用ordinal()不是非常方便？比如这样写：
//
//String task = Weekday.MON.ordinal() + "/ppt";
//saveToFile(task);
//但是，如果不小心修改了枚举的顺序，编译器是无法检查出这种逻辑错误的。要编写健壮的代码，就不要依靠ordinal()的返回值。因为enum本身是class，
//所以我们可以定义private的构造方法，并且，给每个枚举常量添加字段：

/*public class 枚举类 {
    public static void main(String[] args) {
        Weekday day = Weekday.SAT;
        if (day.dayValue == 6 || day.dayValue == 0) {
            System.out.println("Work at home!");
            System.out.println(day.dayValue);
        } else {
            System.out.println("Work at office!");
        }
    }
}

enum Weekday {
    MON(1), TUE(2), WED(3), THU(4), FRI(5), SAT(6), SUN(0);

    public final int dayValue;

    private Weekday(int dayValue) {
        this.dayValue = dayValue;
    }
}*/

//相当于：
//public class 枚举类 {
//    public static void main(String[] args) {
//        Weekday day = Weekday.SAT;
//        if (day.dayValue == 6 || day.dayValue == 0) {
//            System.out.println("Work at home!");
//            System.out.println(day.dayValue);
//        } else {
//            System.out.println("Work at office!");
//        }
//    }
//}
//final class Weekday  {
////	public static final Weekday MON=new Weekday(1);
////	public static final Weekday TUE=new Weekday(2);
////	public static final Weekday WED=new Weekday(3);
////	public static final Weekday THU=new Weekday(4);
////	public static final Weekday FRI=new Weekday(5);
////	public static final Weekday SAT=new Weekday(6);
////	public static final Weekday SUN=new Weekday(0);
//	public static final Weekday MON=new Weekday(1),
//	                            TUE=new Weekday(2),
//	                            WED=new Weekday(3),
//	                            THU=new Weekday(4),
//	                            FRI=new Weekday(5),
//	                            SAT=new Weekday(6),
//	                            SUN=new Weekday(0);
//	public final int dayValue;
//	private Weekday(int dayValue) {
//		this.dayValue=dayValue;
//	}
//}


//这样就无需担心顺序的变化，新增枚举常量时，也需要指定一个int值。

//注意：枚举类的字段也可以是非final类型，即可以在运行期修改，但是不推荐这样做！
//默认情况下，对枚举常量调用toString()会返回和name()一样的字符串。但是，toString()可以被覆写，而name()则不行。我们可以给Weekday添加toString()方法：

//enum
public class 枚举类 {
   public static void main(String[] args) {
       Weekday day = Weekday.SUN;
       if (day.dayValue == 6 || day.dayValue == 0) {
           System.out.println("Today is " + day + ". Work at home!"+day.ordinal());//Today is 星期日g. Work at home!
       } else {
           System.out.println("Today is " + day + ". Work at office!");
       }
   }
}

enum Weekday {
   MON(1, "星期一","a"), TUE(2, "星期二","b"), WED(3, "星期三","c"), THU(4, "星期四","d"), FRI(5, "星期五","e"), SAT(6, "星期六","f"), SUN(0, "星期日","g");

//相当于：
//class Weekday{
//	public static final Weekday MON=new Weekday(1,"星期一","a"), 
//			  					TUE=new Weekday(2, "星期二","b"), 
//			  					WED=new Weekday(3, "星期三","c"), 
//			  					THU=new Weekday(4, "星期四","d"), 
//			  					FRI=new Weekday(5, "星期五","e"), 
//			  					SAT=new Weekday(6, "星期六","f"), 
//			  					SUN=new Weekday(0, "星期日","g");

   public final int dayValue;
   private final String chinese;
   private final String x;
   private Weekday(int dayValue, String chinese,String x) {
       this.dayValue = dayValue;
       this.chinese = chinese;
       this.x=x;
   }
   
   @Override
   public String toString() {
       return this.chinese+this.x;
   }
}

//覆写toString()的目的是在输出时更有可读性。(注意：判断枚举常量的名字，要始终使用name()方法，绝不能调用toString()！)


//《switch》
//最后，枚举类可以应用在switch语句中。因为枚举类天生具有类型信息和有限个枚举常量，所以比int、String类型更适合用在switch语句中：

// switch
//public class 枚举类 {
//    public static void main(String[] args) {
//        Weekday day = Weekday.SUN;
//        switch(day) {
//        case MON:
//        case TUE:
//        case WED:
//        case THU:
//        case FRI:
//            System.out.println("Today is " + day + ". Work at office!");
//            break;
//        case SAT:
//        case SUN:
//            System.out.println("Today is " + day + ". Work at home!");
//            break;
//        default:
//            throw new RuntimeException("cannot process " + day);
//        }
//    }
//}
//
//enum Weekday {
////    MON, TUE, WED, THU, FRI, SAT, SUN;
//	MON(1, "星期一"), TUE(2, "星期二"), WED(3, "星期三"), THU(4, "星期四"), FRI(5, "星期五"), SAT(6, "星期六"), SUN(0, "星期日");
//    public final int dayValue;
//    private final String chinese;
//
//    private Weekday(int dayValue, String chinese) {
//        this.dayValue = dayValue;
//        this.chinese = chinese;
//    }
//    
//    @Override
//    public String toString() {
//    	return this.chinese;
//    }
//}

//加上default语句，可以在漏写某个枚举常量时自动报错，从而及时发现错误。

//《迭代枚举元素》

/*public class 枚举类 {
    public static void main(String[] args) {
//        Weekday day = Weekday.SUN;
        for (Weekday mday:Weekday.values()) {
        	System.out.print(mday);//星期一星期二星期三星期四星期五星期六星期日
        }
    }
}

enum Weekday {
//    MON, TUE, WED, THU, FRI, SAT, SUN;
	MON(1, "星期一"), TUE(2, "星期二"), WED(3, "星期三"), THU(4, "星期四"), FRI(5, "星期五"), SAT(6, "星期六"), SUN(0, "星期日");
    public final int dayValue;
    private final String chinese;

    private Weekday(int dayValue, String chinese) {
        this.dayValue = dayValue;
        this.chinese = chinese;
    }
    
    @Override
    public String toString() {
    	return this.chinese;
    }
}*/


//《枚举类成员》
//枚举跟普通类一样可以用自己的变量、方法和构造函数，构造函数只能使用 private 访问修饰符，所以外部无法调用。
//枚举既可以包含具体方法，也可以包含抽象方法。 如果枚举类具有抽象方法，则枚举类的每个实例都必须实现它。

/*enum Color{
    RED, GREEN, BLUE;
 
    // 构造函数
    private Color() {
        System.out.println("Constructor called for : " + this.toString());
    }
 
    public void colorInfo() {
        System.out.println("Universal Color");
    }
}
 
public class 枚举类{    
    // 输出
    public static void main(String[] args){
        Color c1 = Color.RED;
        System.out.println(c1);
        c1.colorInfo();
    }
}*/
//执行以上代码输出结果为：
//
//Constructor called for : RED
//Constructor called for : GREEN
//Constructor called for : BLUE
//RED
//Universal Color


//《枚举类中的抽象方法实现，需要枚举类中的每个对象都对其进行实现。》

//enum Color{
//    RED{
//        public String getColor(){//枚举对象实现抽象方法
//            return "红色";
//        }
//    },
//    GREEN{
//        public String getColor(){//枚举对象实现抽象方法
//            return "绿色";
//        }
//    },
//    BLUE{
//        public String getColor(){//枚举对象实现抽象方法
//            return "蓝色";
//        }
//    };
//    public abstract String getColor();//定义抽象方法
//}
//
//public class 枚举类{
//    public static void main(String[] args) {
//        for (Color c:Color.values()){
//            System.out.print(c.getColor() + "、");
//        }
//    }
//}



//Java使用enum定义枚举类型，它被编译器编译为final class Xxx extends Enum { … }；
//
//通过name()获取常量定义的字符串，注意不要使用toString()；
//
//通过ordinal()返回常量定义的顺序（无实质意义）；
//
//可以为enum编写构造方法、字段和方法
//
//enum的构造方法要声明为private，字段强烈建议声明为final；
//
//enum适合用在switch语句中。


